using Microsoft.VisualStudio.TestTools.UnitTesting;
using MySpring;

namespace TestMySpring
{
	/// <summary>
	/// Summary description for Aspects
	/// </summary>
	[TestClass]
	public class Aspects
	{
		#region Additional test attributes

		//
		// You can use the following additional attributes as you write your tests:
		//
		// Use ClassInitialize to run code before running the first test in the class
		// [ClassInitialize()]
		// public static void MyClassInitialize(TestContext testContext) { }
		//
		// Use ClassCleanup to run code after all tests in a class have run
		// [ClassCleanup()]
		// public static void MyClassCleanup() { }
		//
		// Use TestInitialize to run code before running each test 
		// [TestInitialize()]
		// public void MyTestInitialize() { }
		//
		// Use TestCleanup to run code after each test has run
		// [TestCleanup()]
		// public void MyTestCleanup() { }
		//

		#endregion

		private class Class5_1
		{
		}

		private class Class5_2
		{
		}

		[TestMethod]
		public void Should_5_SingletoneCreationAspect()
		{
			int callCount = 0;
			object lastCreationParameter = null;
			Factory<Class5_1>.SingletoneCreationAspect += new Factory<Class5_1>.Args(delegate(Class5_1 obj)
				{
					callCount++;
					lastCreationParameter = obj;
				});


			object q = Factory<Class5_2>.Singletone;
			Assert.AreEqual(0, callCount);
			Assert.AreEqual(null, lastCreationParameter);
			Class5_1 test = Factory<Class5_1>.Singletone;
			Assert.AreEqual(1, callCount);
			Assert.AreEqual(test, lastCreationParameter);
			Assert.IsNotNull(Factory<Class5_1>.Singletone);
			Assert.AreEqual(1, callCount);
		}

		private class Class5b_1
		{
		}

		private class Class5b_2
		{
		}

// common object handlers disallow to test weak referanced instances
		private void commonAspect5b(object obj)
		{
			lastCommonCreationParameter = obj;
			callCommonCount++;
		}

		private int callCommonCount = 0;
		private object lastCommonCreationParameter = null;

		[TestMethod]
		public void Should_5b_SingletoneCreationAspectWithCommon()
		{
			try
			{
				int callCount = 0;
				object lastCreationParameter = null;
				Factory<Class5b_1>.SingletoneCreationAspect += new Factory<Class5b_1>.Args(delegate(Class5b_1 obj)
					{
						callCount++;
						lastCreationParameter = obj;
					});

				Factory<object>.SingletoneCreationAspect += new Factory<object>.Args(commonAspect5b);

				object q = Factory<Class5b_2>.Singletone;
				Assert.AreEqual(0, callCount);
				Assert.AreEqual(1, callCommonCount);
				Assert.AreEqual(null, lastCreationParameter);
				Assert.AreEqual(q, lastCommonCreationParameter);
				Class5b_1 test = Factory<Class5b_1>.Singletone;
				Assert.AreEqual(1, callCount);
				Assert.AreEqual(2, callCommonCount);
				Assert.AreEqual(test, lastCreationParameter);
				Assert.AreEqual(test, lastCommonCreationParameter);
				Assert.IsNotNull(Factory<Class5b_1>.Singletone);
				Assert.AreEqual(1, callCount);
				Assert.AreEqual(2, callCommonCount);
			}
			finally
			{
				Factory<object>.SingletoneCreationAspect -= new Factory<object>.Args(commonAspect5b);
			}
		}


		private class Class6WithFlag
		{
			public bool flag;
		}

		private class Clacc6OtherClass{}

		[TestMethod]
		public void Should6_SingletoneRetrivalAspect()
		{
			int callCount = 0;
			int callCommonCount = 0;
			Factory<Class6WithFlag>.SingletoneRetrivalAspect += new Factory<Class6WithFlag>.Args(delegate(Class6WithFlag obj)
				{
					callCount++;
					obj.flag = true;
				});

			Factory<object>.SingletoneRetrivalAspect += new Factory<object>.Args(delegate(object obj) { callCommonCount++; });

			object q = Factory<Clacc6OtherClass>.Singletone;
			Assert.AreEqual(0, callCount);
			Assert.AreEqual(1, callCommonCount);
			Assert.IsTrue(Factory<Class6WithFlag>.Singletone.flag);
			Assert.AreEqual(1, callCount);
			Assert.AreEqual(2, callCommonCount);
			Assert.IsTrue(Factory<Class6WithFlag>.Singletone.flag);
			Assert.AreEqual(2, callCount);
			Assert.AreEqual(3, callCommonCount);
		}

		public interface IFirst
		{
			int ProcessedCount { get; set; }
		}

		public interface ISecond : IFirst
		{
		}

		public interface IThird : ISecond
		{
		}

		public class CBase
		{
			private int processedCount;

			public int ProcessedCount
			{
				get { return processedCount; }
				set { processedCount = value; }
			}
		}

		public class CNext : CBase, IThird
		{
			private CNext()
			{
			}
		}


		[TestMethod]
		public void Should_InvokeRetrivalAspectForImplementedInterfaces()
		{
			Assert.Inconclusive("Not Implemented");
			Factory<IFirst>.SingletoneRetrivalAspect +=
				new Factory<IFirst>.Args(delegate(IFirst obj) { obj.ProcessedCount++; });

			CNext test = Factory<CNext>.Singletone;
			Assert.AreEqual(1, test.ProcessedCount);
			test = Factory<CNext>.Singletone;
			Assert.AreEqual(2, test.ProcessedCount);
		}

		[TestMethod]
		public void Should_worksWithObject_aBugWithDoubleCallingDelegate()
		{
			int called = 0;
			Factory<object>.SingletoneRetrivalAspect += new Factory<object>.Args(delegate { called++; });
			object test = Factory<object>.Singletone;
			Assert.AreEqual(1, called);
			Assert.AreEqual(test, Factory<object>.Singletone);
			Assert.AreEqual(2, called);
		}
	}
}